class_name Player
extends CharacterBody2D

enum State{
	IDLE,
	RUNNING,
	JUMPING,
	FALLING,
	LANDING,
	WALL_SLIDING,
	WALL_JUMPING,
	ATTACK_1,
	ATTACK_2,
	ATTACK_3,
}
const GROUND_STATE := [
		State.IDLE, 
		State.RUNNING, 
		State.LANDING,
		State.ATTACK_1,
		State.ATTACK_2,
		State.ATTACK_3
	]
const RUN_SPEED := 160.0
const JUMP_VELOCITY := -310.0
const WALL_JUMP_VELOCITY := Vector2(380,-280)
const FLOOR_ACCELERATIONS := RUN_SPEED / 0.2
const AIR_ACCELERATIONS := RUN_SPEED / 0.1

@export var can_combo := false

var default_gravity := ProjectSettings.get("physics/2d/default_gravity") as float
var is_first_tick := false
var is_combo_requestd := false

var attack_power :int = 1
@onready var animation_player = $AnimationPlayer
@onready var coyote_timer: Timer = $CoyoteTimer
@onready var jump_request_timer: Timer = $JumpRequestTimer
@onready var graphics: Node2D = $Graphics
@onready var foot_checker: RayCast2D = $Graphics/FootChecker
@onready var hand_checker: RayCast2D = $Graphics/HandChecker
@onready var state_machine: StateMachine = $StateMachine


func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("jump"):
		jump_request_timer.start()
	if event.is_action_released("jump") :
		jump_request_timer.stop()
		if velocity.y < JUMP_VELOCITY/2:
			velocity.y = JUMP_VELOCITY/2
	if  event.is_action_pressed("atack") and can_combo:
		is_combo_requestd = true

func get_currery_attack_power() -> int:
	match state_machine.current_state:
		State.ATTACK_1:
			attack_power = 1
		State.ATTACK_2:
			attack_power = 2
		State.ATTACK_3:
			attack_power = 3
		_ :
			attack_power = 1
	return attack_power

func tick_physics(state: State, delta: float) ->void:
	match state:
		State.IDLE:
			move(default_gravity, delta)
		State.RUNNING:
			move(default_gravity, delta)
		State.JUMPING:
			move(0.0 if is_first_tick else default_gravity, delta)
		State.FALLING:
			move(default_gravity, delta)
		State.LANDING:
			stand(default_gravity, delta)
		State.WALL_SLIDING:
			move(default_gravity/3, delta)
			graphics.scale.x = get_wall_normal().x
		State.WALL_JUMPING:
			if state_machine.state_time < 0.1:
				stand(0.0 if is_first_tick else default_gravity, delta)
				graphics.scale.x = get_wall_normal().x
			else:
				move(default_gravity, delta)
		State.ATTACK_1,State.ATTACK_2,State.ATTACK_3:
			stand(default_gravity, delta)
	is_first_tick = false
	
	
	

func move(gravity: float, delta: float) -> void:
	var direction := Input.get_axis("move_left", "move_right")
	var accelerations := FLOOR_ACCELERATIONS if is_on_floor() else AIR_ACCELERATIONS
	velocity.x = move_toward(velocity.x, direction*RUN_SPEED, accelerations * delta)
	velocity.y += gravity*delta
	if !is_zero_approx(direction):
		graphics.scale.x = -1 if direction < 0 else 1
		
	move_and_slide()

func get_next_state(state: State) -> State:
	var can_jump := is_on_floor() or coyote_timer.time_left > 0
	var is_jumping := can_jump and jump_request_timer.time_left > 0
	if is_jumping:
		return State.JUMPING
	var direction := Input.get_axis("move_left", "move_right")
	var is_standing := is_zero_approx(direction) and is_zero_approx(velocity.x)
	
	if state in GROUND_STATE and not is_on_floor():
		return State.FALLING 
	
	match state:
		State.IDLE:
			if Input.is_action_just_pressed("atack"):
				return State.ATTACK_1
			if not is_standing:
				return State.RUNNING
		State.RUNNING:
			if Input.is_action_just_pressed("atack"):
				return State.ATTACK_1
			if is_standing:
				return State.IDLE
		State.JUMPING:
			if velocity.y >= 0 :
				return State.FALLING
		State.FALLING:
			if is_on_floor():
				return State.LANDING if is_standing else State.RUNNING
			if can_wall_slide():
				return State.WALL_SLIDING
		State.LANDING:
			if not is_standing:
				return State.RUNNING
			if not animation_player.is_playing():
				return State.IDLE
		State.WALL_SLIDING:
			if jump_request_timer.time_left > 0 and not is_first_tick:
				return State.WALL_JUMPING
			if is_on_floor():
				return State.IDLE
			if not is_on_wall():
				return State.FALLING
		State.WALL_JUMPING:
			if can_wall_slide() and not is_first_tick:
				return State.WALL_SLIDING
			if velocity.y >= 0:
				return State.FALLING
		State.ATTACK_1:
			if not animation_player.is_playing():
				return State.ATTACK_2 if is_combo_requestd else State.IDLE
		State.ATTACK_2:
			if not animation_player.is_playing():
				return State.ATTACK_3 if is_combo_requestd else State.IDLE
		State.ATTACK_3:
			if not animation_player.is_playing():
				return State.IDLE
	return state
	
func transition_state(from: State, to: State) -> void:
	
	print("[%s] %s => %s" % [
		Engine.get_physics_frames(),
		State.keys()[from] if from != -1 else "<START>",
		State.keys()[to],
	])
	
	if from not in GROUND_STATE and to in GROUND_STATE:
		coyote_timer.stop()
	match to:
		State.IDLE:
			animation_player.play("idle")
		State.RUNNING:
			animation_player.play("running")
		State.JUMPING:
			animation_player.play("jump")
			velocity.y = JUMP_VELOCITY
			coyote_timer.stop()
			jump_request_timer.stop()
		State.FALLING:
			animation_player.play("falling")
			if from in GROUND_STATE:
				coyote_timer.start()
		State.LANDING:
			animation_player.play("landing")
		State.WALL_SLIDING:
			animation_player.play("wall_sliding")
		State.WALL_JUMPING:
			animation_player.play("jump")
			velocity = WALL_JUMP_VELOCITY
			velocity.x *= get_wall_normal().x
			jump_request_timer.stop()
		State.ATTACK_1:
			animation_player.play("atack_1")
			is_combo_requestd = false
		State.ATTACK_2:
			animation_player.play("atack_2")
			is_combo_requestd = false
		State.ATTACK_3:
			animation_player.play("atack_3")
			is_combo_requestd = false
	is_first_tick = true

func stand(gravity:float, delta: float) -> void:
	var accelerations := FLOOR_ACCELERATIONS if is_on_floor() else AIR_ACCELERATIONS
	velocity.x = move_toward(velocity.x, 0.0, accelerations * delta)
	velocity.y += gravity*delta
	move_and_slide()
	
func can_wall_slide() -> bool:
	return is_on_wall() and hand_checker.is_colliding() and foot_checker.is_colliding()


func _on_hurtbox_hurt(hixbox: Variant) -> void:
	pass # Replace with function body.
